package xyz.haijin.zt.mysql.mapper.impl;

import xyz.haijin.zt.core.exception.BusinessException;
import xyz.haijin.zt.core.annotation.Db;
import xyz.haijin.zt.core.annotation.Table;
import xyz.haijin.zt.core.db.DbConnection;
import xyz.haijin.zt.core.db.DbFactory;
import xyz.haijin.zt.mysql.mapper.BaseMapper;
import xyz.haijin.zt.core.util.BaseUtil;

import java.lang.reflect.Field;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author liuhaijin
 * @date 2022/4/2
 */
public class BaseMapperImpl<T> implements BaseMapper<T> {

    protected static final SimpleDateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private DbConnection connection;

    private String dbName;

    private Class<T> beanClass;

    public BaseMapperImpl(Class<T> clazz, String db) {
        connection = DbFactory.getInstance(db);
        dbName = db;
        beanClass = clazz;
    }

    public BaseMapperImpl(Class<T> clazz) {
        dbName = clazz.getAnnotation(Db.class).value();
        connection = DbFactory.getInstance(dbName);
        beanClass = clazz;
    }


    @Override
    public List<T> list() {
        String tableColumn = BaseUtil.getTableColumn(beanClass);
        String tableName = beanClass.getAnnotation(Table.class).value();
        String sql = "select "+tableColumn+" from " + tableName;
        List<String> fieldList = BaseUtil.getFieldList(beanClass);
        Map<String, Field> fieldMap = BaseUtil.getFieldMap(beanClass);
        return BaseUtil.findBySql(sql,connection,beanClass,fieldList,fieldMap);
    }

    @Override
    public T getOneById(Object id) throws Exception {
        List<Object> ids = BaseUtil.getIds(beanClass);
        if (ids.size() > 2) {
            throw new BusinessException("主键的数量不能超过两个");
        }
        String tableColumn = BaseUtil.getTableColumn(beanClass);
        String tableName = beanClass.getAnnotation(Table.class).value();
        String sql = "select "+tableColumn+" from " + tableName + " where `" + ids.get(0) + "`=?";
        List<String> fieldList = BaseUtil.getFieldList(beanClass);
        Map<String, Field> fieldMap = BaseUtil.getFieldMap(beanClass);
        Object[] objects = new Object[]{id};
        List<T> result = BaseUtil.findPreparedBySql(objects, sql, connection, beanClass, fieldList, fieldMap);
        if (result.size() > 2) {
            throw new BusinessException("查询存在多个数据项");
        }
        return result.get(0);
    }

    @Override
    public List<T> inByIds(Object... values) throws SQLException {
        List<Object> ids = BaseUtil.getIds(beanClass);
        if (ids.size() > 2) {
            throw new BusinessException("主键的数量不能超过两个");
        }
        if (values == null || values.length == 0) {
            throw new BusinessException("传入的数据不能为空");
        }
        String tableColumn = BaseUtil.getTableColumn(beanClass);
        String tableName = beanClass.getAnnotation(Table.class).value();
        StringBuilder sqlBuilder = new StringBuilder("select ")
                .append(tableColumn)
                .append(" from ")
                .append(tableName)
                .append(" where `")
                .append(ids.get(0))
                .append("`")
                .append(" in (");
        for (int i = 0; i < values.length; i++) {
            if (i == values.length - 1) {
                sqlBuilder.append("?");
            } else {
                sqlBuilder.append("?,");
            }
        }
        sqlBuilder.append(")");
        String sql = sqlBuilder.toString();
        List<String> fieldList = BaseUtil.getFieldList(beanClass);
        Map<String, Field> fieldMap = BaseUtil.getFieldMap(beanClass);
        return BaseUtil.findPreparedBySql(values, sql, connection, beanClass, fieldList, fieldMap);
    }

    @Override
    public boolean batchInsert(List<T> instances) throws Exception {
        List<String> fieldList = BaseUtil.getFieldList(beanClass);
        Map<String, Field> fieldMap = BaseUtil.getFieldMap(beanClass);
        String tableName = beanClass.getAnnotation(Table.class).value();
        StringBuilder builder = new StringBuilder();
        builder.append("insert into `").append(tableName)
                .append("`(");
        List<String> values = new ArrayList<>();
        for (int i = 0; i < instances.size(); i++) {
            T t = instances.get(i);
            int count = 0;
            StringBuilder valueStr = new StringBuilder();
            for (String key : fieldList) {
                Field field = fieldMap.get(key);
                Class<?> parameterType = field.getType();
                Object value = field.get(t);
                if (value != null) {
                    if (String.class.equals(parameterType)) {
                        value = "'" + value + "'";
                    } else if (Date.class.equals(parameterType)) {
                        value = "'" + DATETIME_FORMAT.format((Date) value) + "'";
                    }

                    if (count > 0) {
                        if (i == 0) {
                            builder.append(",");
                        }
                        valueStr.append(",");
                    }
                    if (i == 0) {
                        builder.append("`" + key + "`");
                    }
                    valueStr.append(value);
                    count++;
                }
            }
            values.add(valueStr.toString());
        }
        builder.append(") values");
        for (int i = 0; i < values.size(); i++) {
            builder.append("(");
            builder.append(values.get(i));
            if(i == values.size()-1) {
                builder.append(")");
            } else {
                builder.append("),");
            }
        }
        return connection.execute(builder.toString());
    }
}
